package com.cloud.point.concurrent.general;

import java.io.Serializable;

import lombok.extern.slf4j.Slf4j;

/**
 * volatile的使用
 *
 * @author 24373
 * @version 1.0
 * @date 2024-06-17 12:42
 */
@Slf4j
public class TestVolatile {

    public static void main(String[] args) throws InterruptedException {

        test1();
        //test2();

    }

    /**
     * volatile 在多线程下不能保证原子性
     * cpu指令调度会影响结果（指令交错执行）
     */
    static volatile int i = 0;

    private static void test1() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            for (int j = 0; j < 1000; j++) {
                i++;
            }
        });
        Thread t2 = new Thread(() -> {
            for (int j = 0; j < 1000; j++) {
                i--;
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        log.info("{}", i);
    }

    /**
     * 单例模式验证
     */
    private static void test2() {
        for (int j = 0; j < 10000; j++) {
            new Thread(() -> {
                Singleton singleton = Singleton.newInstance();
                log.info("{}", singleton);
            }).start();
        }
    }

    /**
     * 单例模式
     */
    static class Singleton implements Serializable {
        private static final long serialVersionUID = -4488552652869327617L;

        /**
         * 设置成私有防止其它对象创建
         */
        private Singleton() {
        }

        private static volatile Singleton INSTANCE;

        /**
         * 对外暴露实例唯一创建方法
         */
        public static Singleton newInstance() {
            /**
             * INSTANCE 变量没有被 synchronized 完全管理；当内部发生指令重排时，会影响到外部值的判定
             */
            if (INSTANCE == null) {
                synchronized (Singleton.class) {
                    if (INSTANCE == null) {
                        /**
                         * 对象初始化和地址赋值不是原子操作，是会发生指令重排的
                         * 加了 volatile 关键字后，构成写屏障，会禁止初始化与赋值发生的指令重排
                         */
                        INSTANCE = new Singleton();
                    }
                }
            }
            return INSTANCE;
        }

        /**
         * readResolve是Java 序列化机制中的一个回调方法，它在对象反序列化过程中被调用，允许开发者自定义反序列化后的对象
         * 当单例对象实现了序列化接口，防止反序列化破坏单例；
         */
        public Object readResolve() {
            return INSTANCE;
        }

    }

}